package net.yegong.matrix;

/**
 * @author cooper
 */
public class DiagonalMatrix implements SpecialMatrix {
	public DiagonalMatrix(int nRow, int nCol) {
		this.nRow = nRow;
		this.nCol = nCol;
		diag = new float[Math.min(nRow, nCol)];
	}

	public DiagonalMatrix(float[] diag) {
		this.nRow = diag.length;
		this.nCol = diag.length;
		this.diag = diag;
	}

	public DiagonalMatrix(float[] diag, int nRow, int nCol) {
		this.nRow = nRow;
		this.nCol = nCol;
		this.diag = diag;
	}

	public int getColumnsCount() {
		return nCol;
	}

	public int getRowsCount() {
		return nRow;
	}

	public DiagonalMatrix transpose() {
		return new DiagonalMatrix(diag, nCol, nRow);
	}

	public void transposeMe() {
		int tmp = nCol;
		nCol = nRow;
		nRow = tmp;
	}

	public float[] getArray() {
		return diag;
	}

	public float get(int index) {
		return diag[index];
	}

	public float get(int i, int j) {
		if (i == j)
			return diag[i];
		else
			return 0;
	}

	public void set(int ij, float value) {
		diag[ij] = value;
	}

	public Matrix toMatrix() {
		int len = diag.length;
		Matrix ret = new Matrix(nRow, nCol);
		for (int i = 0; i < len; ++i) {
			ret.set(i, i, diag[i]);
		}
		return ret;
	}

	public DiagonalMatrix add(DiagonalMatrix m) {
		int len1 = diag.length;
		if (nCol != m.nCol || nRow != m.nRow)
			throw new MatrixDimensionException();
		DiagonalMatrix ret = clone();
		float[] diag2 = ret.getArray();
		for (int i = 0; i < len1; ++i)
			diag2[i] += m.diag[i];
		return ret;
	}

	public DiagonalMatrix add(DiagonalMatrix m, float alpha, float beta) {
		int len1 = diag.length;
		if (nCol != m.nCol || nRow != m.nRow)
			throw new MatrixDimensionException();
		DiagonalMatrix ret = clone();
		float[] diag2 = ret.getArray();
		for (int i = 0; i < len1; ++i)
			diag2[i] = alpha * diag[i] + beta * m.diag[i];
		return ret;
	}

	public Matrix add(Matrix m) {
		int nRow2 = m.getRowsCount();
		int nCol2 = m.getColumnsCount();
		int len = diag.length;
		if (nRow != nRow2 || nCol != nCol2)
			throw new MatrixDimensionException();

		Matrix ret = new Matrix(len, len);
		float value;
		for (int i = 0; i < len; ++i) {
			value = diag[i] + m.get(i, i);
			ret.set(i, i, value);
		}
		return ret;
	}

	public Matrix add(Matrix m, float alpha, float beta) {
		int nRow2 = m.getRowsCount();
		int nCol2 = m.getColumnsCount();
		int len = diag.length;
		if (nRow != nRow2 || nCol != nCol2)
			throw new MatrixDimensionException();

		Matrix ret = new Matrix(len, len);
		float value;
		for (int i = 0; i < len; ++i) {
			value = alpha * diag[i] + beta * m.get(i, i);
			ret.set(i, i, value);
		}
		return ret;
	}

	public void scale(float alpha) {
		int len = diag.length;
		for (int i = 0; i < len; ++i)
			diag[i] *= alpha;
	}

	public DiagonalMatrix multiply(float alpha) {
		int len = diag.length;
		DiagonalMatrix ret = clone();
		float[] diag2 = ret.getArray();
		for (int i = 0; i < len; ++i)
			diag2[i] *= alpha;
		return ret;
	}

	public DiagonalMatrix leftMultiply(DiagonalMatrix m) {
		if (nCol != m.nRow)
			throw new MatrixDimensionException();
		DiagonalMatrix ret = new DiagonalMatrix(nRow, m.nCol);
		float[] diag2 = ret.getArray();
		int len = Math.min(diag.length, m.diag.length);
		for (int i = 0; i < len; ++i)
			diag2[i] = diag[i] * m.diag[i];
		return ret;
	}

	public DiagonalMatrix rightMultiply(DiagonalMatrix m) {
		return m.leftMultiply(this);
	}

	public Matrix leftMultiply(Matrix m) {
		int nRow2 = m.nRow;
		int nCol2 = m.nCol;
		if (nCol != nRow2)
			throw new MatrixDimensionException();
		Matrix ret = new Matrix(nRow, nCol2);
		int len = diag.length;
		for (int i = 0; i < len; ++i) {
			for (int j = 0; j < nCol2; ++j) {
				ret.array[i + j * nRow] = m.array[i + j * nRow2] * diag[i];
			}
		}
		return ret;
	}

	public Matrix rightMultiply(Matrix m) {
		int nRow2 = m.nRow;
		int nCol2 = m.nCol;
		if (nRow != nCol2)
			throw new MatrixDimensionException();
		Matrix ret = new Matrix(nRow2, nCol);
		int len = diag.length;
		for (int i = 0; i < len; ++i) {
			for (int j = 0; j < nRow2; ++j) {
				ret.array[j + i * nRow2] = m.array[j + i * nRow2] * diag[i];
			}
		}
		return ret;
	}

	public float trace() {
		float sigma = 0.0f;
		for (float d : diag)
			sigma += d;
		return sigma;
	}

	public float det() {
		float pi = 1;
		for (float d : diag)
			pi *= d;
		return pi;
	}

	public float max() {
		float max = Float.NEGATIVE_INFINITY;
		for (float d : diag)
			if (d > max)
				max = d;
		return max;
	}

	public float maxAbsolute() {
		float max = Float.NEGATIVE_INFINITY;
		float abs;
		for (float d : diag) {
			abs = Math.abs(d);
			if (abs > max)
				max = abs;
		}
		return max;
	}

	public float min() {
		float min = Float.POSITIVE_INFINITY;
		for (float d : diag)
			if (d < min)
				min = d;
		return min;
	}

	public float minAbsolute() {
		float min = Float.POSITIVE_INFINITY;
		float abs;
		for (float d : diag) {
			abs = Math.abs(d);
			if (abs < min)
				min = abs;
		}
		return min;
	}

	@Override
	public DiagonalMatrix clone() {
		return new DiagonalMatrix(MatrixHelper.copy(diag), nRow, nCol);
	}

	@Override
	public String toString() {
		StringBuilder buf = new StringBuilder();
		for (int i = 0; i < nRow; ++i) {
			for (int j = 0; j < nCol; ++j) {
				buf.append(get(i, j));
				buf.append(", ");
			}
			buf.append("\n");
		}
		return buf.toString();
	}

	protected float[] diag;
	protected int nCol;
	protected int nRow;
}
